#-*- encoding:utf8 -*-
import re
from django.db import models as db_models
from django.db.models import Model,ForeignKey
from django.template import loader,Context
from util import loader as myloader
import json

from sms import base

class ModelMetaClass(type):
    def __new__(cls,name,bases,attrs):
        module = attrs.pop('__module__')
        parents = [b for b in bases if isinstance(b, ModelMetaClass)]
        if parents:
            for obj_name, obj in attrs.items():
                Model.add_to_class(obj_name, obj)
        return super(ModelMetaClass, cls).__new__(cls, name, bases, attrs)

class MetroModelBase(object):
    __metaclass__ = ModelMetaClass

class MetroModelAbstract(MetroModelBase):
    manageable = True
    #将一条记录序列化为id,text字典

    primary_key_name = u'id'
    xuexiao_field_name = u'xx'

    #根据角色过滤数据，不同角色需要改写该方法
    @classmethod
    def filter(cls,request):
        try:
            return cls.objects.filter(xx=request.user.xx)
        except:
            return cls.objects.all()

    @classmethod
    def ajax_tree_items(cls,request,role,field):
        return {
            u'id':'',
            u'text':u'%s对象还没有实现读取节点的方法。'%cls.path(),
            u'children':True
        }

    def item(self):
        return {u"id":getattr(self,self.primary_key_name),u"name":unicode(self)}

    @classmethod
    def items(cls,records):
        result = []
        for record in records:
            result.append(record.item())
        return result

    @classmethod
    def path(cls):
        return u"%s.%s"%(cls.__module__,cls.__name__)

    @classmethod
    def get_url(cls):
        url = u"/page/%s/"%cls.path()
        return url

    #获取模版
    @classmethod
    def get_template(cls):
        path = cls.path().replace(u".",u"/")
        path = path.lower()
        path += u'.html'
        try:
            return loader.get_template(path)
        except:
            return loader.get_template(u"page.html")

    #模型名和角色名
    @classmethod
    def model_name_and_role_name(cls,request):
        return request.path.split(u'/')[2:-1]

    #上下文
    @classmethod
    def get_context(cls,request):
        model_name,role_name = cls.model_name_and_role_name(request)
        return Context({
            u'request':request,
            u'search_fields' : cls.search_fields(request),
            u'columns' : cls.fields(request),
            u'edits' : cls.edit_fields(request),
            u'actions' : cls.actions_to_model(request),
            u'model_name' : model_name,
            u'role_name' : role_name,
            u'js_path' : cls.js_path()
        })

    @classmethod
    def js_path(cls):
        return u'scripts/page.js'



    #显示列名
    field_names = []
    #编辑列名
    edit_field_names = []
    #可查找列名
    search_field_names = []
    #可进行操作的动作
    action_names = [u'create',u'edit',u'remove',u'copy',u'excel',u'pdf',u'print',u'search']

    action_config = [
        {
            u'text' : u'新建',
            u'identity' : u'create',
            u'icon' : u''
        },
        {
            u'text' : u'编辑',
            u'identity' : u'edit',
            u'icon' : u''
        },
        {
            u'text' : u'删除',
            u'identity' : u'remove',
            u'icon' : u''
        },
        {
            u'text' : u'复制',
            u'identity' : u'copy',
            u'icon' : u''
        },
        {
            u'text' : u'导出Excel',
            u'identity' : u'excel',
            u'icon' : u''
        },
        {
            u'text' : u'导出PDF',
            u'identity' : u'pdf',
            u'icon' : u''
        },
        {
            u'text' : u'打印',
            u'identity' : u'print',
            u'icon' : u''
        },{
            u'text' : u'筛选',
            u'identity' : u'search',
            u'icon' : u''
        }
    ]

    #将显示列名转换为对应base.py中对应的对象
    @classmethod
    def fields(cls,request):
        _fields = cls._meta.fields + cls._meta.many_to_many
        _columns = []
        for item in cls.field_names:
            if isinstance(item,(str,unicode)):
                _columns.append(cls._meta.get_field_by_name(item)[0])
            elif isinstance(item,dict):
                _columns.append(item)

        _columns = _columns if _columns else _fields

        result = []
        for column in _columns:
            if isinstance(column,db_models.Field):
                if column.name == u'id':
                    continue
                result.append(getattr(base,u'Column%s'%column.__class__.__name__)(request,column))
            elif isinstance(column,dict):
                column_class = column.get(u'column_class')
                params = column.copy()
                del params[u'column_class']
                params[u'request'] = request
                result.append(column_class(**params))
        return result

    #将编辑列名转换为对应base.py中对应的对象
    @classmethod
    def edit_fields(cls,request):
        result = []

        for name in cls.edit_field_names:
            if name==u'id':
                continue
            try:
                # 模型自定义生成编辑字段的方法，如果定义，优先使用，否则使用默认默认方法
                edit_field_method = getattr(cls,u'edit_field_method_%s'%name)
                result.append(edit_field_method(request))
                continue
            except:
                pass
            if isinstance(name,dict):
                params = name.copy()
                if params.has_key(u'edit_class'):
                    edit_class = params.pop(u'edit_class')
                    result.append(edit_class(**params))
                elif params.has_key(u'field_name'):
                    field  = cls._meta.get_field_by_name(params.pop(u'field_name'))[0]
                    edit_class = getattr(base,u'Edit%s'%field.__class__.__name__)
                    params[u'request'] = request
                    params[u'field'] = field
                    result.append(edit_class(**params))
            elif isinstance(name,(unicode,str)):
                field = cls._meta.get_field_by_name(name)[0]
                edit_class = getattr(base,u"Edit%s"%field.__class__.__name__)
                result.append(edit_class(request,field))
            else:
                field = name
                edit_class = getattr(base,u'Edit%s'%field.__class__.__name__)
                result.append(edit_class(request,field))
        return result

    #将查找列名转换为对应base.py中对应的对象
    @classmethod
    def search_fields(cls,request):
        result = []
        for item in cls.search_field_names:
            try:
                # 模型自定义生成查找字段的方法，如果定义，优先使用，否则使用默认默认方法
                search_field_method = getattr(cls,u'search_field_method_%s'%item)
                result.append(search_field_method(request))
                continue
            except:
                pass
            if isinstance(item,dict):
                search_class = item.get(u'search_class')
                params = {key : value for key,value in item.items() if key!=u'search_class'}
                params[u'request'] = request
                params[u'main_model'] = cls
                result.append(search_class(**params))
            elif isinstance(item,(unicode,str)):
                field = cls._meta.get_field_by_name(item)[0]
                search_class = getattr(base,u'Search%s'%field.__class__.__name__)
                result.append(search_class(request,field))
            else:
                field = item
                search_class = getattr(base,u'Search%s'%field.__class__.__name__)
                result.append(search_class(request,field))

        return result

    ##将操作转换为对应base.py中对应的对象
    @classmethod
    def actions_to_model(cls,request):
        result = []
        for action in cls.action_names:
            result.append(base.ActionModel(request,cls,action,action.title()))

        return result

    #将一行数据转换为dict
    def row(self,request,fields):
        result = {}
        for field in fields:
            result[field.name] = field.data(self)
        result[u'id'] = getattr(self,self.primary_key_name)
        return result

    #将record转换为json格式时输出的列
    @classmethod
    def rows_fields(cls,request):
        result = {field.name:field for field in cls.fields(request)}
        for field in cls.edit_fields(request):
            result[field.name] = field
        return result

    #将一组记录转换为json对象
    @classmethod
    def rows(cls,request,records):
        data = []
        fields = cls.rows_fields(request).values()
        for record in records:
            data.append(record.row(request,fields))

        return {
            u'data':data
        }

    @classmethod
    def analysis_post(cls,request):
        result = {
            u'columns' : {},
            u'orders' : {},
            u'draw' : 0,
            u'length' : 0,
            u'start' : 0
        }

        def columns_data(key,value,match_obj):
            num = match_obj.groups()[0]
            result[u'columns'][num] = value

        def order_column(key,value,match_obj):
            num = match_obj.groups()[0]
            orders = result[u'orders'].get(num,{})
            orders[u'name'] = request.POST.get(u'columns[%s][data]'%value)
            result[u'orders'][num] = orders

        def order_dir(key,value,match_obj):
            num = match_obj.groups()[0]
            orders = result[u'orders'].get(num,{})
            orders[u'dir'] = value
            result[u'orders'][num] = orders

        def draw(key,value,match_obj):
            result[u'draw'] = value

        def length(key,value,match_obj):
            result[u'length']  = value

        def start(key,value,match_obj):
            result[u'start'] = value

        patterns = [
            (u'columns\[(\d+)\]\[data\]',columns_data),
            (u'order\[(\d+)\]\[column\]',order_column),
            (u'order\[(\d+)\]\[dir\]',order_dir),
            (u'draw',draw),
            (u'length',length),
            (u'start',start)
        ]
        for key,value in request.POST.items():
            for pattern,math in patterns:
                match_obj = re.match(pattern,key)
                if match_obj:
                    math(key,value,match_obj)

        return result

    #输出数据
    @classmethod
    def datas(cls,request):

        post_data = cls.analysis_post(request)

        records = cls.filter(request)

        total_count = records.count()

        for field in cls.search_fields(request):
            records = field.search(records)

        filter_count = records.count()

        sorting = []
        for index in range(len(post_data[u'orders'].keys())):
            name = post_data[u'orders'][unicode(index)][u'name']
            name = name.split(".")[0]
            direction = post_data[u'orders'][unicode(index)][u'dir']
            if direction == u'desc':
                name = u'-' + name
            sorting.append(name)

        records = records.order_by(*sorting)

        length = int(post_data[u'length'])
        start = int(post_data[u'start'])
        if length<>-1:
            result = cls.rows(request,records[start:(start+length)])
        else :
            result = cls.rows(request,records)

        result[u'draw'] = post_data[u"draw"]
        result[u'recordsFiltered'] = filter_count
        result[u'recordsTotal'] = total_count
        return result

    #数据表操作接口，在视图中根据参数调用add,edit,delete执行具体操作
    @classmethod
    def do_action(cls,request):
        action = request.POST.get(u'action')
        return getattr(cls,u'do_action_%s'%action)(request)


    @classmethod
    def save_instance(cls,request,instance,ID):
        many_to_many_fields = []

        for field in cls.edit_fields(request):
            if issubclass(field.field.__class__,db_models.ManyToManyField):
                many_to_many_fields.append(field)
                continue
            field.setattr(instance,ID)

        instance.save1(request=request)
        for field in many_to_many_fields:
            field.setattr(instance,ID)
            instance.save()

    @classmethod
    def get_primary_keys(cls,request):
        result = []
        for k in request.POST.keys():
            try:
                result.append(re.search(u'data\[(\d+)\]\[id\]', k).groups()[0])
            except:
                pass
        if not result:
            return None
        elif len(result) == 1:
            return int(result[0])
        else:
            return result

    @classmethod
    def do_action_create(cls,request):
        obj = cls()
        cls.save_instance(request,obj,0)
        return cls.rows(request,[obj])


    @classmethod
    def do_action_edit(cls,request):
        def pk():
            for k in request.POST.keys():
                try:
                    return re.search(u'data\[(\d+)\]',k).groups()[0]
                except:
                    pass
            return None

        ID = pk()
        obj = cls.objects.get(pk=ID)
        cls.save_instance(request,obj,ID)
        return cls.rows(request,[obj])

    @classmethod
    def do_action_remove(cls,request):
        pks = cls.get_primary_keys(request)
        if pks is None:
            pks = []
        if isinstance(pks, int):
            pks = [pks]

        start = 0;
        targets = pks[start:start + 100]
        while targets:
            cls.objects.filter(pk__in=targets).delete()
            start += 100
            targets = pks[start:start + 100]
        return {u'data': []}


    def save1(self, force_insert=False, force_update=False, using=None,update_fields=None,request=None):
        model = self.__class__
        try:
            model._meta.get_field_by_name(self.xuexiao_field_name)
            try:
                xx_value = getattr(self,self.xuexiao_field_name)
            except:
                xx_value = None
            xx = request.user.xx
            if xx_value is None and xx is not None:
                setattr(self,self.xuexiao_field_name,xx)
        except:
            pass
        self.save(force_insert=force_insert,force_update=force_update,using=using,update_fields=update_fields)
        pass


class MetroModel(MetroModelAbstract):
    pass



from django.db import models as dmodels
from django.template import loader ,Context
from util.loader import load_member
import json

class BaseField(object):
    def __init__(self,request,field):
        self.request = request
        self.field = field
        self.direction = u''
    @property
    def name(self):
        return self.field.name

    @property
    def verbose_name(self):
        return u'%s'%self.field.verbose_name

    def data(self,obj):
        return getattr(obj,self.name)

    # 确定排序方式
    def ordering(self):
        if self.name in self.field.model._meta.ordering:
            self.direction = u'asc'
            return True
        elif u'-%s'%self.name in self.field.model._meta.ordering:
            self.direction = u'desc'
            return True
        return False

class ColumnGeneratorField(object):
    def __init__(self,request,name,verbose_name):
        self.request = request
        self.__name = name
        self.__verbose_name = verbose_name

    @property
    def name(self):
        return self.__name

    @property
    def verbose_name(self):
        return self.__verbose_name

    def data(self,obj):
        return getattr(obj,self.name)

    def render(self):
        return json.dumps({u"data":self.name})

class ColumnField(BaseField):
    def render(self):
        return json.dumps({u"data":self.name})


class ColumnBooleanField(ColumnField):
    def get_template(self):
        return loader.get_template(u'controls/columns/booleanfield_column.html')

    def get_context(self):
        return Context({
            u'field':self
        })

    def render(self):
        return self.get_template().render(self.get_context())

class ColumnCharField(ColumnField):
    pass

class ColumnMyCharField(ColumnCharField):
    pass

class ColumnMySfzjhCharField(ColumnCharField):
    pass

class ColumnDateField(ColumnField):
    def data(self,obj):
        return unicode(getattr(obj,self.name))


class ColumnDateTimeField(ColumnDateField):
    pass

class ColumnDecimalField(ColumnField):
    pass

class ColumnMyDecimalField(ColumnDecimalField):
    pass

class ColumnEmailField(ColumnCharField):
    pass

class ColumnFilePathField(ColumnField):
    pass

class ColumnFloatField(ColumnField):
    pass

class ColumnMyFloatField(ColumnFloatField):
    pass

class ColumnIntegerField(ColumnField):
    pass

class ColumnMyIntegerField(ColumnIntegerField):
    pass

class ColumnBigIntegerField(ColumnIntegerField):
    pass

class ColumnIPAddressField(ColumnField):
    pass

class ColumnGenericIPAddressField(ColumnField):
    pass

class ColumnNullBooleanField(ColumnField):
    pass

class ColumnPositiveIntegerField(ColumnIntegerField):
    pass

class ColumnPositiveSmallIntegerField(ColumnIntegerField):
    pass

class ColumnSlugField(ColumnCharField):
    pass

class ColumnSmallIntegerField(ColumnIntegerField):
    pass

class ColumnTextField(ColumnField):
    pass

class ColumnTimeField(ColumnField):
    pass

class ColumnURLField(ColumnCharField):
    pass

class ColumnForeignKey(ColumnField):
    def render(self):
        return json.dumps({u"data" : u"%s.name"%self.name})

    def data(self,obj):
        try:
            value = getattr(obj,self.name)
            return value.item()
        except:
            return {u'id':u'',u'name':u''}

class ColumnTreeForeignKey(ColumnForeignKey):
    pass

class ColumnMyAjaxTreeForeignKey(ColumnTreeForeignKey):
    pass

class ColumnManyToManyField(ColumnField):
    def render(self):
        result =  {
            u'data' : self.name,
            u'render' : u'[,].name'
        }
        return json.dumps(result)

    def data(self,obj):
        value = getattr(obj,self.name)
        records = value.all()
        result = []
        for record in records:
            result.append(record.item())

        return result



class SearchField(object):
    def __init__(self,request,field,**kwargs):
        self.request = request
        self.field = field
        self.role_name = self.request.path.split(u'/')[-2]
        self.kwargs = kwargs

    @property
    def template(self):
        name = u'controls/search/%s_search.html'%self.field.__class__.__name__.lower()
        return loader.get_template(name)

    @property
    def context(self):
        return Context({
            u'request' : self.request,
            u'field' : self.field
        })

    def render(self):
        return self.template.render(self.context)

    @property
    def name(self):
        return self.field.name

    @property
    def verbose_name(self):
        return u'%s'%self.field.verbose_name

    def search(self,records):
        return records

class SearchBooleanField(SearchField):
    def search(self,records):
        value = self.request.POST.get(self.field.name,None)
        if value==u'true':
            value = True
        elif value==u'false':
            value = False
        else:
            value = None

        if value is None:
            return records
        q = dmodels.Q()
        q.children.append((self.field.name,value))
        return records.filter(q)


class SearchCharField(SearchField):
    def search(self,records):
        value = self.request.POST.get(self.field.name,None)
        if not value:
            return records
        q = dmodels.Q()
        q.children.append((self.field.name+'__icontains',value))
        return records.filter(q)


class SearchMyCharField(SearchCharField):
    pass

class SearchMySfzjhCharField(SearchMyCharField):
    pass

class SearchDateField(SearchField):
    pass

class SearchDateTimeField(SearchField):
    pass

class SearchDecimalField(SearchField):
    pass

class SearchMyDecimalField(SearchDecimalField):
    pass

class SearchEmailField(SearchCharField):
    pass

class SearchFilePathField(SearchField):
    pass

class SearchFloatField(SearchField):
    pass

class SearchMyFloatField(SearchFloatField):
    pass

class SearchIntegerField(SearchField):
    pass

class SearchMyIntegerField(SearchIntegerField):
    pass

class SearchBigIntegerField(SearchIntegerField):
    pass

class SearchIPAddressField(SearchField):
    pass

class SearchGenericIPAddressField(SearchField):
    pass

class SearchNullBooleanField(SearchField):
    pass

class SearchPositiveIntegerField(SearchIntegerField):
    pass

class SearchPositiveSmallIntegerField(SearchIntegerField):
    pass

class SearchSlugField(SearchCharField):
    pass

class SearchSmallIntegerField(SearchIntegerField):
    pass

class SearchTextField(SearchField):
    pass

class SearchTimeField(SearchField):
    pass

class SearchURLField(SearchCharField):
    pass

class SearchForeignKey(SearchField):
    @property
    def context(self):
        main_model_by_role = load_member(self.request,self.field.rel.to.path(),self.role_name)
        try:
            # 该字段所在数据模型定义了foreignkey_records_filter_（字段名）(request)方法
            #　使用该方法过滤数据
            filter_method = getattr(self.field.model,u'foreignkey_records_filter_%s'%self.field.name)
            records = filter_method(self.request)
        except:
            #　出现异常，使用该字段关联的数据模型的filter(request)方法
            records = main_model_by_role.filter(self.request)
        records = main_model_by_role.items(records)
        return Context({
            u'request' : self.request,
            u'field' : self.field,
            u'options' : records
        })

    def search(self,records):
        value = self.request.POST.get(self.field.name)
        if value:
            try:
                method = getattr(self.field.model,u'searchforeignkey_%s'%self.field.name)
                records = method(self.request,records)
            except:
                q = dmodels.Q()
                q.children.append((u'%s__pk'%self.field.name,value))
                records = records.filter(q)

        return records

class SearchTreeForeignKey(SearchForeignKey):
    @property
    def context(self):
        #return super(SearchTreeForeignKey,self).context
        return Context({
            u'request' : self.request,
            u'field' : self.field,
            u'items' : json.dumps(self.field.rel.to.nodes())
        })

class SearchMyAjaxTreeForeignKey(SearchTreeForeignKey):
    @property
    def context(self):
        params = [u'%s=%s'%(k,v) for k,v in self.kwargs.items()]
        params = u'&'.join(params)
        if params<>u'':
            params = u'?' + params
        model_path = self.field.rel.to.path() if self.field.get_tree_item_from_field_to else self.field.model.path()
        return Context({
            u'request' : self.request,
            u'field' : self.field,
            u'ajax_url' : u'/ajax_tree_items/%s/%s/%s/%s/%s'%(self.field.model.path(),model_path,self.role_name,self.name,params)
        })

class SearchForeignKey1(SearchField):
    def __init__(self,request,main_model,model1,field_name1):
        self.request = request
        self.role_name = self.request.path.split(u'/')[-2]
        self.main_model = main_model
        self.model1 = model1
        self.field_name1 = field_name1

    @property
    def name(self):
        return u'searchforeignkey1_%s'%self.field_name1

    @property
    def context(self):
        main_model_by_role = load_member(self.request,self.model1.path(),self.role_name)
        try:
            # 该字段所在数据模型定义了foreignkey_records_filter_（字段名）(request)方法
            #　使用该方法过滤数据
            filter_method = getattr(self.main_model,u'foreignkey_records_filter_%s'%self.field_name1)
            records = filter_method(self.request)
        except:
            #　出现异常，使用该字段关联的数据模型的filter(request)方法
            records = main_model_by_role.filter(self.request)

        records = main_model_by_role.items(records)
        return Context({
            u'request' : self.request,
            u'main_model' : self.main_model,
            u'model1' : self.model1,
            u'field_name1' : self.field_name1,
            u'options' : records,
            u'role_name' : self.role_name,
            u'field_verbose_name1' : self.model1._meta.verbose_name,
        })

    @property
    def template(self):
        name = u'controls/search/searchforeign1_search.html'
        return loader.get_template(name)

    def search(self,records):
        value = self.request.POST.get(self.field_name1)
        if value:
            try:
                method = getattr(self.main_model,u'searchforeignkey1_%s'%self.field_name1)
                records = method(self.request,records)
            except:
                q = dmodels.Q()
                q.children.append((u'%s__pk'%self.field.name,value))
                records = records.filter(q)

        return records


class SearchForeignKey2(SearchForeignKey1):
    def __init__(self,request,main_model,model1,model2,field_name1,field_name2):
        super(SearchForeignKey2,self).__init__(request,main_model,model1,field_name1)
        # self.request = request
        # self.role_name = self.request.path.split(u'/')[-2]
        # self.main_model = main_model
        # self.model1 = model1
        self.model2 = model2
        # self.field_name1 = field_name1
        self.field_name2 = field_name2

    @property
    def name(self):
        return u'searchforeignkey2_%s'%self.field_name1

    @property
    def context(self):
        c = super(SearchForeignKey2,self).context
        c[u'model2']  = self.model2
        c[u'field_name2'] = self.field_name2
        c[u'field_verbose_name2'] = self.model2._meta.verbose_name
        return c

        # main_model_by_role = load_member(self.request,self.model1.path(),self.role_name)
        # records = main_model_by_role.objects.all()
        # records = main_model_by_role.items(records)
        # return Context({
        #     u'request' : self.request,
        #     u'main_model' : self.main_model,
        #     u'model1' : self.model1,
        #     u'model2' : self.model2,
        #     u'field_name1' : self.field_name1,
        #     u'field_name2' : self.field_name2,
        #     u'field_verbose_name1' : self.model1._meta.verbose_name,
        #     u'field_verbose_name2' : self.model2._meta.verbose_name,
        #     u'options' : records,
        #     u'role_name' : self.role_name
        # })

    def search(self,records):
        value1 = self.request.POST.get(self.field_name1,None)
        value2 = self.request.POST.get(self.field_name2,None)
        if value1:
            try:
                method = getattr(self.main_model,u'searchforeignkey_%s'%self.field_name1)
                records = method(self.request,records)
            except:
                field = self.main_model._meta.get_field_by_name(self.field_name1)[0]
                if (field):
                    q = dmodels.Q()
                    q.children.append((u'%s__pk'%field.name,value1))
                    records = records.filter(q)
        if value2:
            try:
                method = getattr(self.main_model,u'searchforeignkey_%s'%self.field_name2)
                records = method(self.request,records)
            except:
                try:
                    field = self.main_model._meta.get_field_by_name(self.field_name2)[0]
                except:
                    field = None

                if (field):
                    q = dmodels.Q()
                    q.children.append((u'%s__pk'%field.name,value1))
                    records = records.filter(q)
        return records

    @property
    def template(self):
        name = u'controls/search/searchforeign2_search.html'
        return loader.get_template(name)

class SearchForeignKey3(SearchForeignKey2):
    def __init__(self,request,main_model,model1,model2,model3,field_name1,field_name2,field_name3):
        super(SearchForeignKey3,self).__init__(request,main_model,model1,model2,field_name1,field_name2)
        self.model3 = model3
        self.field_name3 = field_name3

    @property
    def context(self):
        result = super(SearchForeignKey3,self).context
        result[u'model3'] = self.model3
        result[u'field_name3'] = self.field_name3
        result[u'field_verbose_name3'] = u'%s'%self.model3._meta.verbose_name
        return result

    @property
    def template(self):
        name = u'controls/search/searchforeign3_search.html'
        return loader.get_template(name)


    def search(self,records):
        records = super(SearchForeignKey3,self).search(records)
        value3 = self.request.POST.get(self.field_name3,None)
        if value3:
            try:
                method = getattr(self.main_model,u'searchforeignkey_%s'%self.field_name1)
                records = method(self.request,records)
            except:
                try:
                    field = self.main_model._meta.get_field_by_name(self.field_name3)[0]
                    if (field):
                        q = dmodels.Q()
                        q.children.append((u'%s__pk'%field.name,value3))
                        records = records.filter(q)
                except:
                    pass

        return records


class EditField(BaseField):
    def __init__(self,request,field,editable=True,unique=False,**kwargs):
        super(EditField,self).__init__(request,field)
        self.role_name = request.path.split(u'/')[-2]
        self.editable = not self.field.unique if editable else False #editable
        self.kwargs = kwargs
        self.__unique = True if unique else field.unique

    def render(self):
        result = {}
        result[u'label'] = u'%s'%self.field.verbose_name
        result[u'name'] = self.name
        result[u'type'] = u'mtext'
        result[u'editable'] = self.editable
        result[u'rules'] = self.rules()
        return json.dumps(result)

    def key(self,pk):
        return u'data[%s][%s]'%(pk,self.field.name)


    def value(self,pk):
        return self.field.to_python(self.request.POST.get(self.key(pk)))

    def setattr(self,obj,pk):
        setattr(obj,self.name,self.value(pk))

    def required(self):
        return not (self.field.null and self.field.blank)

    def unique(self):
        result = {u'type':u'get'}
        result[u'url'] = u'/validator/%s/%s/'%(self.field.model.path(),self.name)
        result[u'cache'] = False
        result[u'async'] = False
        return result

    def rules(self):
        result = {}
        if self.required():
            result[u'required'] = True
        if self.__unique:
            result[u'remote']  = self.unique()
        return result

    @property
    def rule_name(self):
        return self.name

    def validate_rules(self):
        return json.dumps(self.rules())

class EditBooleanField(EditField):
    def render(self):
        result = {}
        result[u'label'] = u'%s'%self.field.verbose_name
        result[u'name'] = self.field.name
        result[u'type'] = u'mradio'
        result[u'rules'] = self.rules()
        result[u'editable'] = self.editable
        result[u'options'] = [
            {u'label':u'是',u'value':True},
            {u'label':u'否',u'value':False}
        ]
        return json.dumps(result)


    def value(self,pk):
        v = self.request.POST.get(self.key(pk))
        if v in (u'true',u'false'):
            v = v.title()
        return self.field.to_python(v)


class EditCharField(EditField):
    def max_length(self):
        return self.field.max_length

    def rules(self):
        result = super(EditCharField,self).rules()
        result[u'maxlength']  = self.max_length()
        return result

    def required(self):
        return not self.field.blank

class EditMyCharField(EditCharField):
    def equalto(self):
        return self.field.to_field

    def min_length(self):
        return self.field.min_length

    def rules(self):
        result = super(EditMyCharField,self).rules()
        if self.field.min_length:
            result[u'minlength'] = self.min_length()
        if self.field.to_field:
            result[u'equalTo'] = u'#%s'%self.name
        return result

class EditMySfzjhCharField(EditCharField):
    def rules(self):
        result = super(EditMySfzjhCharField,self).rules()
        result[u'isidcardno'] = True
        return result

class EditDateField(EditField):
    def build_render(self):
        result = {}
        result[u'label'] = u'%s'%self.field.verbose_name
        result[u'name'] = self.field.name
        result[u'type'] = u'mdate'
        result[u'rules'] = self.rules()
        result[u'editable'] = self.editable

        return result

    def render(self):
        return json.dumps(self.build_render())

    def data(self,obj):
        return unicode(getattr(obj,self.name))

    def date(self):
        return True

    def rules(self):
        result = super(EditDateField,self).rules()
        result[u'date'] = self.date()
        return result

class EditDateTimeField(EditDateField):
    def build_render(self):
        result = super(EditDateTimeField,self).build_render()
        result[u'type'] = u'mdatetime'
        return result

    def rules(self):
        result = super(EditDateTimeField,self).rules()
        try:
            result.pop(u"date")
        except:
            pass
        result[u'datetime'] = True
        return result

class EditDecimalField(EditField):
    def number(self):
        return True

    def rules(self):
        result = super(EditDecimalField,self).rules()
        result[u'number'] = self.number()
        return result

class EditMyDecimalField(EditDecimalField):
    def max(self):
        return self.field.max

    def min(self):
        return self.field.min

    def rules(self):
        result = super(EditMyDecimalField)
        if self.field.max:
            result[u'max'] = self.max()
        if self.field.min:
            result[u'min'] = self.min()
        return result

class EditEmailField(EditCharField):
    def email(self):
        return True;

    def rules(self):
        result = super(EditEmailField,self).rules()
        result[u'email'] = self.email()
        return result

class EditFilePathField(EditField):
    pass

class EditFloatField(EditField):
    def number(self):
        return True

    def rules(self):
        result = super(EditFloatField,self).rules()
        result[u'number'] = self.number()
        return result

class EditMyFloatField(EditFloatField):
    def max(self):
        return self.field.max

    def min(self):
        return self.field.min

    def rules(self):
        result = super(EditMyFloatField,self).rules()
        if self.field.max:
            result[u'max'] = self.max()
        if self.field.min:
            result[u'min'] = self.min()

        return result


class EditIntegerField(EditField):
    def digits(self):
        return True

    def rules(self):
        result = super(EditIntegerField,self).rules()
        result[u'digits'] = self.digits()
        return result

class EditMyIntegerField(EditIntegerField):
    def max(self):
        return self.field.max

    def min(self):
        return self.field.min

    def rules(self):
        result = super(EditMyIntegerField,self).rules()
        if self.field.max:
            result[u'max'] = self.max()
        if self.field.min:
            result[u'min'] = self.min()
        return result

class EditBigIntegerField(EditIntegerField):
    pass

class EditIPAddressField(EditField):
    pass

class EditGenericIPAddressField(EditField):
    pass

class EditNullBooleanField(EditField):
    pass

class EditPositiveIntegerField(EditIntegerField):
    pass

class EditPositiveSmallIntegerField(EditIntegerField):
    pass

class EditSlugField(EditCharField):
    pass

class EditSmallIntegerField(EditIntegerField):
    pass

class EditTextField(EditField):
    pass

class EditTimeField(EditField):
    pass

class EditURLField(EditCharField):
    def url(self):
        return True

    def rules(self):
        result = super(EditURLField,self).rules()
        result[u'url'] = self.url()
        return result

class EditForeignKey(EditField):
    def render(self):
        result = {}
        result[u'label'] = u'%s'%self.field.verbose_name
        result[u'name'] = u'%s.id'%self.field.name
        result[u'type'] = u'mselect'
        result[u'rules'] = self.rules()
        result[u'editable'] = self.editable
        result[u'options'] = []
        model = load_member(self.request,self.field.rel.to.path(),self.role_name)
        for record in model.objects.all():
            result[u'options'].append({u'label':unicode(record),u'value':record.id})

        return json.dumps(result)

    @property
    def rule_name(self):
        return u'%s.id'%self.name


    def key(self,pk):
        return u'data[%s][%s][id]'%(pk,self.field.name)


    def value(self,pk):
        v = self.request.POST.get(self.key(pk))
        try:
            q = dmodels.Q()
            q.children.append((self.field.rel.to.primary_key_name,v))
            return self.field.rel.to.objects.get(q)
        except:
            return None

    def data(self,obj):
        try:
            value = getattr(obj,self.name)
        except:
            value = None
        if value:
            return value.item()
        else:
            return {u'id':u'',u'name':u''}

class EditTreeForeignKey(EditForeignKey):
    def render(self):
        result = {}
        result[u'label'] = u'%s'%self.field.verbose_name
        result[u'name'] = u'%s.id'%self.field.name
        result[u'type'] = u'treeselect1'
        result[u'rules'] = self.rules()
        result[u'editable'] = self.editable
        model = load_member(self.request,self.field.rel.to.path(),self.role_name)
        result[u'items'] = model.nodes()

        return json.dumps(result)

class EditMyAjaxTreeForeignKey(EditForeignKey):
    def render(self):
        params = [u'%s=%s'%(k,v) for k,v in self.kwargs.items()]
        params = u'&'.join(params)
        if params<>u'':
            params = u'?' + params

        model_path = self.field.rel.to.path() if self.field.get_tree_item_from_field_to else self.field.model.path()
        result = {}
        result[u'label'] = u'%s'%self.field.verbose_name
        result[u'name'] = u'%s.id'%self.field.name
        result[u'type'] = u'ajaxtreeselect'
        result[u'rules'] = self.rules()
        result[u'editable'] = self.editable
        result[u'ajax_url'] = u'/ajax_tree_items/%s/%s/%s/%s/%s'%(self.field.model.path(),model_path,self.role_name,self.name,params)
        return json.dumps(result)


class EditManyToManyField(EditField):
    def render(self):
        result = {}
        result[u'label'] = u'%s'%self.field.verbose_name
        result[u'name'] = u'%s[].id'%self.field.name
        result[u'type'] = u'mmselect'
        result[u'rules'] = self.rules()
        result[u'editable'] = self.editable
        result[u'options'] = []
        model = load_member(self.request,self.field.rel.to.path(),self.role_name)
        for record in model.objects.all():
            result[u'options'].append({u'label':unicode(record),u'value':record.id})
        return json.dumps(result)

    def many_to_many_count(self,pk):
        return int(self.request.POST.get(u'data[%s][%s-many-count]'%(pk,self.name)))


    def value(self,pk):
        result = []
        for index in range(self.many_to_many_count(pk)):
            ID = self.request.POST.get(u'data[%s][%s][%s][id]'%(pk,self.field.name,index))
            result.append(self.field.rel.to.objects.get(pk=ID))
        return result

    def data(self,obj):
        value = getattr(obj,self.name)
        records = value.all()
        result = []
        for record in records:
            result.append(record.item())

        return result